﻿using GN.Pay.TradeChannel.DefaultImpl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RabbitMQ.GNClient;
using RabbitMQ.GNClient.Events;
using Abp.Dependency;
using GN.Pay.Core.Services;
using GN.Pay.Core.Entities;
using GN.Pay.Core.Values;
using GN.Pay.Core.Values.Channel;
using static GN.Pay.Core.Consts.ServiceConstant;
using GN.Pay.Core.Services.Impl;

namespace GN.Pay.Core.Tasks.Queue.Impl
{

    /// <summary>
    /// 
    /// </summary>
    class ChannelPayNotifyConsumerQueue : AConsumerQueue<TradeOrderQueryResultValue>, IChannelPayNotifyConsumerQueue
    {
        /// <summary>
        /// 
        /// </summary>
        public IPayNotifyService PayNotifyService { get; set; }

        public ChannelPayNotifyConsumerQueue(IIocManager iocManager)
            : base(QueueType.ChannelPayNotify, iocManager)
        {
            this.PayNotifyService = NullPayNotifyService.Instance;
        }

        /// <summary>
        /// 
        /// </summary>
        protected override ushort MaxPrefetchCount
        {
            get
            {
                return 10;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="eventConsumer"></param>
        /// <param name="data"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        protected override async Task Consumer(IEventingConsumer eventConsumer,
            TradeOrderQueryResultValue data, DeliverEventArgs e)
        {
            await Task.Run(() =>
            {
                if (string.IsNullOrWhiteSpace(e.Message.MessageId))
                {
                    this.Logger.ErrorFormat("通道付款通知无签名信息");
                    eventConsumer.Channel.Ack(e.DeliveryTag);
                    return;
                }
                if (!data.MessageSignVerify(Consts.Start.MessageSign, e.Message.MessageId))
                {
                    this.Logger.ErrorFormat("通道付款通知签名不正确");
                    eventConsumer.Channel.Ack(e.DeliveryTag);
                    return;
                }
                bool isAck = true;
                try
                {
                    this.UpdateUnitOfWork(() =>
                    {
                        var tradeCacheService = this.IocManager.Resolve<ITradeCacheService>();
                        var tradeAccountBookService = this.IocManager.Resolve<ITradeAccountBookService>();
                        TradePayApply tradePayApply;
                        var account = tradeAccountBookService.Accounting(data, out tradePayApply);
                        if (tradePayApply != null && account != null)
                        {
                            var book = account.TradeAccountBook;
                            var app = tradeCacheService.GetMerchantAppInfo(book.AppId);
                            if (app == null || (string.IsNullOrWhiteSpace(tradePayApply.NotifyUrl)
                                && string.IsNullOrWhiteSpace(tradePayApply.ReturnUrl)))
                            {
                                return;
                            }
                            var message = new PayNotifyData();
                            message.ApplyId = tradePayApply.Id;
                            message.OrderNo = book.OrderNo;
                            message.OrderTime = book.OrderTime;
                            message.OrderMoney = book.OrderMoney;
                            message.Subject = book.Subject;
                            message.Body = book.Body;
                            message.MemberNo = book.MemberNo;
                            message.Remark = book.Remark;
                            message.ExtraParam = tradePayApply.ExtraParam;
                            message.TradeNo = account.Id;
                            message.ChannelId = account.ChannelId;
                            message.ApplyTime = account.ApplyTime;
                            message.PayTime = account.PayTime;
                            message.BookTime = account.BookTime;
                            message.PayFee = account.PayFee;
                            message.PayMoney = account.PayMoney;
                            message.TotalPayFee = account.TradeAccountBook.PayFee;
                            message.TotalPayMoney = account.TradeAccountBook.PayMoney;
                            message.TotalPayCount = account.TradeAccountBook.PayCount;
                            message.TradeState = account.TradeAccountBook.TradeState;
                            var channel = tradeCacheService.GetTradeChannel(book.AppId, message.ChannelId);
                            if (channel != null)
                            {
                                message.ChannelName = channel.ChannelName;
                            }
                            else
                            {
                                message.ChannelName = data.ChannelName;
                            }
                            var notifyService = this.IocManager.Resolve<ITradeNotifyService>();
                            var notify = notifyService.PullNotify(app, TradeNotifyType.Pay, tradePayApply.NotifyUrl, tradePayApply.ReturnUrl, message);
                            PayNotifyService.PaySuccess(notify);
                        }
                    });
                }
                catch (Exception err)
                {
                    isAck = false;
                    this.Logger.Error(err.Message, err);
                    this.DelayConsumer(eventConsumer, data, e, new TimeSpan(0, 0, 10));
                    throw err;
                }
                finally
                {
                    if (isAck)
                    {
                        eventConsumer.Channel.Ack(e.DeliveryTag);
                    }
                }
            });
        }
    }
}
